08. Colorizing

L3 07 Color

Colorizing

One of the powerful things about ObjectAnimator, which might not be obvious from the examples so far, is that it can animate anything, as long as there is a property that the animator can access.

Step 1: Animating an arbitrary property

Here is one simple example of animating a single property on an object. This time, that property isn’t an android.util.Property object, but is instead a property exposed via a setter, View.setBackgroundColor(int). Since you cannot refer to an android.util.Property object directly, like you did before with ALPHA, etc., you will use the approach of passing in the name of the property as a String. The name is then mapped internally to the appropriate setter/getter information on the target object.

For this example, you will fill in the colorizer() function, which is called when you click on colorizerButton. In this animation, you will change the color of the star field background from black to red (and back).

  1. First, you will need an ObjectAnimator that can act on the appropriate type. You could use the ObjectAnimator.ofInt() factory method, since View.setBackgroundColor(int) takes an int, but… that would give us unexpected results. In the colorizer() function, create and run such an animator to see the problem:
var animator = ObjectAnimator.ofInt(star.parent,"backgroundColor", Color.BLACK, Color.RED).start()
  1. Now run your application and click on colorizerButton. Isn’t that demo flashy? In fact, it’s a bit too flashy - it flashes between many different colors on the way from BLACK to RED. Without getting too much into the details of it, the problem is that the animation is interpreting raw integers as colors. Animating between two integer values does not necessarily yield the same result as animating between the colors that those two integers represent.

Step 2: Animate colors, not integers

What you need, instead, is an animator that knows how to interpret (and animate between) color values, rather than simply the integers that represent those colors.

  1. Use a different factory method for the animator, ObjectAnimator.ofArgb(). Try the code again, using this factory method instead:
var animator = ObjectAnimator.ofArgb(star.parent,"backgroundColor", Color.BLACK, Color.RED).start()

Now run the app. You’ll see that it smoothly animates from black to red, without those weird color flashes along the way.

Note: The ofArgb() method is the reason that this app builds against minSdk 21; the rest of the functionality of the app can be run on earlier SDKs, but ofArgb() was introduced in the Lollipop release. It is also possible to animate color values on earlier releases, involving TypeEvaluators, and the use of ArgbEvaluator specifically. We used ofArgb() in this lesson instead for simplicity.

The other thing to notice about this construction of the ObjectAnimator is the property: instead of specifying one of the View properties, like ALPHA, you are simply passing in the string “backgroundColor”. When you do this, the system searches for setters and getters with that exact spelling using reflection. It caches references to those methods and calls them during the animation, instead of calling the Property set/get functions as the previous animations did.

Step 3: Fade [back] to black

Anyway, back to our animation. We currently have the ability to animate from black to red… and that’s where it stays. If you click the button again, it will animate again, but it always ends up at red, because the animation explicitly animates from black to and end value of red.

  1. Change the animation to take a little longer to run, by setting an explicit duration, and then animate back to black. You should also disable the button during the animation, as you did with the other animations, by calling the extension function created earlier. Here’s what that complete function looks like:
private fun colorizer() {
    var animator = ObjectAnimator.ofArgb(star.parent,
        "backgroundColor", Color.BLACK, Color.RED)
    animator.setDuration(500)
    animator.repeatCount = 1
    animator.repeatMode = ObjectAnimator.REVERSE
    animator.disableViewDuringAnimation(bgColor)
    animator.start()
}

That's all there is to it. This animation is very similar to all of the rest you've set up in this lab, except for the use of the “backgroundColor” string for the property name. This doesn’t seem all that different from what you did before, except that it means you can use ObjectAnimator to animate literally anything that has a setter/getter. For example, you could have a custom View with a property called lineLength, that sets the length of some line segment in your UI (maybe using custom drawing code in an onDraw() override). Passing in “lineLength” to the animator constructor would result in animating that line length, because the system maps that string to the underlying property setter in your custom view code.

You can, and should, use ObjectAnimator for all property animations in your application. There are other kinds of animations you can create in applications (including whole-application animation choreography, using MotionLayout, but for individual property animations, ObjectAnimator is the way to go.